﻿/*-----------------------------------------------
// File: Story3dLogic.cs
// Description: 
// Author: Shaobing	492057342@qq.com
-----------------------------------------------*/
using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public delegate void StoryEndCallback();
public class Story3dLogic : MonoBehaviour
{
    public Animation storyAnim;
    public Camera storyCam;
    public string startAnimName;
    public string storyId;


    public bool isStoryStart = false;
    public float curDeltaTime;

    StoryEndCallback endCallback = null;

    float duration;
    string backgroundMusic;

    List<StorySoundInfo> allSoundInfo = new List<StorySoundInfo>();
    Queue<StorySoundInfo> soundInfo;
    StorySoundInfo currentSoundInfo = null;

    List<StorySubtitleInfo> subTitleInfo = new List<StorySubtitleInfo>();
    StorySubtitleInfo curSubtitle = null;

    [System.Serializable]
    public class StoryActor {
        public string modelName;
        public SkinnedMeshRenderer meshRenderer;
    }

    public List<StoryActor> storyActors;


    Dictionary<string, List<StoryChangeFaceInfo>> faceInfo;

    public IEnumerator LoadResource()
    {
        yield return 1;
        int taskCount = 0;
        foreach (var audio in allSoundInfo)
        {
            StartCoroutine(AudioManager.Instance.LoadAudioResource(audio.audioName, () => { taskCount--; }));
            taskCount++;
        }

        while (taskCount > 0)
        {
            yield return null;
        }

        isStoryStart = true;
        curDeltaTime = 0f;
        storyAnim.Play(startAnimName);

    }


    public void UnloadResource() {
        foreach (var audio in allSoundInfo) {
            AudioManager.Instance.UnloadAudioResource(audio.audioName);
        }
    }


    public void SetStoryEndCallBack(StoryEndCallback callback)
    {
        endCallback = callback;
    }

    public void StoryStart()
    {
        storyAnim.cullingType = AnimationCullingType.AlwaysAnimate;
        RemoveUILayerFromCameraCullingMask();
        var dict = Dict.Blo.Dict3dStoryBlo.GetTable3dStory(storyId);
        if (dict != null)
        {
            duration = (float)dict.StoryDuration;
            backgroundMusic = dict.StoryMusic;
            ParseStorySoundInfo(dict.StorySound);
            ParseStoryFaceInfo(dict.StoryChangeFace);
            ParseStorySubtitle(dict.StorySubtitle);
            if (!string.IsNullOrEmpty(backgroundMusic))
            {
                AudioManager.Instance.PlayBackgroundMusic(backgroundMusic);
            }
            StartCoroutine(LoadResource());
        }
        else {
            Debug.LogError("StoryId:" + storyId + " not exist in dict!!");
        }
    }

    public void Skip()
    {
        curDeltaTime = duration;
    }

    void Update()
    {
        if (isStoryStart)
        {
            curDeltaTime += Time.deltaTime;
            if (currentSoundInfo == null)
            {
                if (soundInfo.Count > 0)
                {
                    currentSoundInfo = soundInfo.Dequeue();
                }
            }
            if (currentSoundInfo != null)
            {
                if (currentSoundInfo.time <= curDeltaTime)
                {
                    AudioManager.Instance.PlaySingle(currentSoundInfo.audioName);
                    currentSoundInfo = null;
                }
            }

            if (curSubtitle == null) {
                foreach (var t in subTitleInfo) {
                    if (curDeltaTime >= t.startTime && curDeltaTime <= t.stopTime) {
                        curSubtitle = t;
                        break;
                    }
                }
            }
            if (curSubtitle != null) {
                if (curDeltaTime >= curSubtitle.startTime && curDeltaTime <= curSubtitle.stopTime)
                {
                    ShowText(curSubtitle.text);
                }
                else {
                    HideText();
                    curSubtitle = null;
                }
            }

            if (curDeltaTime >= duration)
            {
                StoryEnd();
            }
        }
    }

    public void ShowText(string str) {
        SubTitlePanel.Instance.Show();
        SubTitlePanel.Instance.SetText(str);

    }
    public void HideText() {
        SubTitlePanel.Instance.Hide();
    }

    public void StoryEnd()
    {
        UnloadResource();
        if (endCallback != null)
        {
            endCallback();
        }
        isStoryStart = false;
        storyAnim.Stop();
    }

    void ParseStorySubtitle(string infoStr) {
        var arr = infoStr.Split(new char[1] { '#' }, System.StringSplitOptions.RemoveEmptyEntries);
        List<StorySubtitleInfo> list = new List<StorySubtitleInfo>();
        foreach (var info in arr) {
            var arr0 = info.Split(new char[1] { '=' }, System.StringSplitOptions.RemoveEmptyEntries);
            if (arr0.Length == 2) {
                string text = TableTextBlo.GetText(arr0[1]);
                var arr1 = arr0[0].Split(new char[1] { ',' }, System.StringSplitOptions.RemoveEmptyEntries);
                if (arr1.Length == 2) {
                    float startTime = float.Parse(arr1[0]);
                    float stopTime = float.Parse(arr1[1]);
                    StorySubtitleInfo subTitle = new StorySubtitleInfo(startTime, stopTime, text);
                    list.Add(subTitle);
                }
            }
        }
        list.Sort(delegate (StorySubtitleInfo x, StorySubtitleInfo y)
        {
            return x.startTime.CompareTo(y.startTime);
        });
        subTitleInfo = list; 
    }

    void ParseStoryFaceInfo(string infoStr) {
        var arr = infoStr.Split(new char[1] { ';' }, System.StringSplitOptions.RemoveEmptyEntries);
        faceInfo = new Dictionary<string, List<StoryChangeFaceInfo>>();
        foreach (var info in arr) {
            var arr0 = info.Split(new char[1] { ':' }, System.StringSplitOptions.RemoveEmptyEntries);
            if (arr0.Length == 2) {
                string modelName = arr0[0];
                var arr1 = arr0[1].Split(new char[1] { '#' }, System.StringSplitOptions.RemoveEmptyEntries);
                List<StoryChangeFaceInfo> changeInfos = new List<StoryChangeFaceInfo>();
                foreach (var _info in arr1)
                {
                    var arr2 = _info.Split(new char[1] { '=' }, System.StringSplitOptions.RemoveEmptyEntries);
                    if (arr2.Length == 2) {
                        string faceId = arr2[1];
                        var arr3 = _info.Split(new char[1] { ',' }, System.StringSplitOptions.RemoveEmptyEntries);
                        if (arr3.Length == 2) {
                            float startTime = float.Parse(arr3[0]);
                            float stopTime = float.Parse(arr3[1]);
                            StoryChangeFaceInfo changeInfo = new StoryChangeFaceInfo(startTime, stopTime, faceId);
                            changeInfos.Add(changeInfo);
                        }
                    }
                }

                if (faceInfo.ContainsKey(modelName))
                {
                    faceInfo[modelName].AddRange(changeInfos);
                }
                else {
                    faceInfo[modelName] = changeInfos;
                }

            }
        }
    }



    void ParseStorySoundInfo(string infoStr)
    {
        var arr = infoStr.Split(new char[1] { '#' }, System.StringSplitOptions.RemoveEmptyEntries);
        allSoundInfo = new List<StorySoundInfo>();
        foreach (var info in arr)
        {
            var arr0 = info.Split(new char[1] { '=' }, System.StringSplitOptions.RemoveEmptyEntries);
            if (arr0.Length == 2)
            {
                float time = float.Parse(arr0[1]);
                string name = arr0[0];
                StorySoundInfo clip = new StorySoundInfo(name, time);
                allSoundInfo.Add(clip);
            }
        }
        allSoundInfo.Sort(delegate (StorySoundInfo x, StorySoundInfo y)
        {
            return x.time.CompareTo(y.time);
        });
        soundInfo = new Queue<StorySoundInfo>();
        foreach (var info in allSoundInfo)
        {
            soundInfo.Enqueue(info);
        }
        currentSoundInfo = null;
    }

    public void RemoveUILayerFromCameraCullingMask()
    {
        int uiLayer = LayerMask.NameToLayer("UI");
        if (storyCam != null)
        {
            storyCam.cullingMask = storyCam.cullingMask & (~(1 << uiLayer));
        }
    }

}

public class StorySubtitleInfo
{
    public float startTime;
    public float stopTime;
    public string text;
    public StorySubtitleInfo(float st, float et, string str)
    {
        this.startTime = st;
        this.stopTime = et;
        this.text = str;
    }
}

public class StorySoundInfo
{
    public float time;
    public string audioName;

    public StorySoundInfo(string _name, float _time)
    {
        audioName = _name;
        time = _time;
    }
}

public class StoryChangeFaceInfo
{
    public float startTime;
    public float stopTime;
    public string faceId;

    public StoryChangeFaceInfo(float startTime, float stopTime, string faceId)
    {
        this.startTime = startTime;
        this.stopTime = stopTime;
        this.faceId = faceId;
    }
}